package com.huxi.lang.validation.predicate;

import static com.huxi.lang.type.VTypeUtils.compare;

import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 范围类型枚举
 * 
 * @author jian.wu
 *
 */
public enum RangeType {
	/**
	 * 双闭区间: []
	 */
	CLOSED_ALL(true, true),
	/**
	 * 半闭半开区间: [)
	 */
	CLOSED_LOWER(true, false),
	/**
	 * 半开半闭区间: (]
	 */
	CLOSED_UPPER(false, true),
	/**
	 * 双开区间: ()
	 */
	CLOSED_NONE(false, false);

	private final boolean includeLower;
	private final boolean includeUpper;

	private RangeType(boolean lower, boolean upper) {
		this.includeLower = lower;
		this.includeUpper = upper;
	}

	public boolean test(Number n, Number min, Number max) {
		if (min != null) {
			if (includeLower) {
				if (compare(n, min) < 0) {
					return false;
				}
			} else {
				if (compare(n, min) <= 0) {
					return false;
				}
			}
		}
		if (max != null) {
			if (includeUpper) {
				if (compare(n, max) > 0) {
					return false;
				}
			} else {
				if (compare(n, max) >= 0) {
					return false;
				}
			}
		}
		return true;
	}

	public <T extends java.lang.Comparable<T>> boolean test(T v, T min, T max) {
		if (min != null) {
			if (includeLower) {
				if (v.compareTo(min) < 0) {
					return false;
				}
			} else {
				if (v.compareTo(min) <= 0) {
					return false;
				}
			}
		}
		if (max != null) {
			if (includeUpper) {
				if (v.compareTo(max) > 0) {
					return false;
				}
			} else {
				if (v.compareTo(max) >= 0) {
					return false;
				}
			}
		}
		return true;
	}

	public <T> boolean test(T v, T min, T max, Comparator<T> c) {
		if (min != null) {
			if (includeLower) {
				if (c.compare(v, min) < 0) {
					return false;
				}
			} else {
				if (c.compare(v, min) <= 0) {
					return false;
				}
			}
		}
		if (max != null) {
			if (includeUpper) {
				if (c.compare(v, max) > 0) {
					return false;
				}
			} else {
				if (c.compare(v, max) >= 0) {
					return false;
				}
			}
		}
		return true;
	}

	public boolean lower() {
		return includeLower;
	}

	public boolean upper() {
		return includeUpper;
	}

	public static String format(RangeType range, Object min, Object max) {
		if (range == null) {
			range = RangeType.CLOSED_LOWER;
		}
		StringBuilder sb = new StringBuilder();
		sb.append(range.includeLower ? "[" : "(").append(min != null ? min : "").append(',')
				.append(max != null ? max : "").append(range.includeUpper ? "]" : ")");
		return sb.toString();
	}

	private static Pattern patter = Pattern.compile("^[\\[\\(][^\\[\\]\\(\\),]*,[^\\[\\]\\(\\),]*[\\]\\)]$");

	public static RangeType parse(String text) {
		return parse(text, 0);
	}

	public static RangeType parse(String text, int start) {
		if (text == null || text.isEmpty()) {
			return null;
		}
		Matcher m = patter.matcher(text);
		if (start != 0) {
			m = m.region(start, text.length());
		}
		if (m.matches()) {
			boolean lower = text.startsWith("[", start);
			boolean upper = text.endsWith("]");
			if (lower) {
				return upper ? CLOSED_ALL : CLOSED_LOWER;
			} else {
				return upper ? CLOSED_UPPER : CLOSED_NONE;
			}
		}
		return null;
	}
}
